﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System;
using System.Collections.Generic;
using System.Linq;

namespace XCI.Core
{
    /// <summary>
    /// 静态缓存,线程安全,独占锁
    /// </summary>
    /// <typeparam name="TKey">键类型</typeparam>
    /// <typeparam name="TValue">值类型</typeparam>
    public class StaticCache<TKey, TValue>
    {
        private readonly static object lockObj = new object();
        private readonly Dictionary<TKey, TValue> data = new Dictionary<TKey, TValue>(1000);

        /// <summary>
        /// 获取缓存数量
        /// </summary>
        public int Count
        {
            get { lock (lockObj) { return data.Count; } }
        }

        /// <summary>
        /// 获取缓存对象使用指定的键
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <param name="factory">找不到缓存时创建对象回调函数</param>
        /// <returns>返回缓存值</returns>
        public TValue Get(TKey key, Func<TValue> factory = null)
        {
            if (key == null) throw new ArgumentNullException(nameof(key), "请指定缓存键");
            lock (lockObj)
            {
                if (data.TryGetValue(key, out TValue val))
                {
                    return val;
                }
                else if (factory != null)
                {
                    val = factory();
                    data[key] = val;
                    return val;
                }
            }
            return default(TValue);
        }

        /// <summary>
        /// 确定缓存中是否包含指定的键值
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>存在返回True</returns>
        public bool Contains(TKey key)
        {
            if (key == null) throw new ArgumentNullException(nameof(key), "请指定缓存键");
            lock (lockObj)
            {
                return data.ContainsKey(key);
            }
        }

        /// <summary>
        /// 初始化缓存
        /// </summary>
        /// <param name="action">初始化回调函数</param>
        public void Init(Action<Dictionary<TKey, TValue>> action)
        {
            if (action == null) throw new ArgumentNullException(nameof(action), "请指定初始化回调函数");
            lock (lockObj)
            {
                data.Clear();
                action(data);
            }
        }

        /// <summary>
        /// 设置缓存对象使用指定的键
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <param name="value">缓存值</param>
        /// <returns>返回缓存值</returns>
        public void Set(TKey key, TValue value)
        {
            if (key == null) throw new ArgumentNullException(nameof(key), "请指定缓存键");
            lock (lockObj)
            {
                data[key] = value;
            }
        }

        /// <summary>
        /// 批量设置缓存对象
        /// </summary>
        /// <param name="dic">缓存字典</param>
        public void Set(Dictionary<TKey, TValue> dic)
        {
            if (dic == null || dic.Count == 0) throw new ArgumentNullException(nameof(dic), "请指定缓存字典");
            lock (lockObj)
            {
                foreach (var item in dic)
                {
                    if (item.Key == null) continue;
                    data[item.Key] = item.Value;
                }
            }
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key">缓存键</param>
        public void Remove(TKey key)
        {
            if (key == null) throw new ArgumentNullException(nameof(key), "请指定缓存键");
            lock (lockObj)
            {
                data.Remove(key);
            }
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="keys">缓存键数组</param>
        public void Remove(TKey[] keys)
        {
            if (keys == null || keys.Length == 0) throw new ArgumentNullException(nameof(keys), "请指定缓存键数组");

            lock (lockObj)
            {
                foreach (var key in keys)
                {
                    if (key == null) continue;
                    data.Remove(key);
                }
            }
        }

        /// <summary>
        /// 清空缓存
        /// </summary>
        public void Clear()
        {
            lock (lockObj)
            {
                data.Clear();
            }
        }

        /// <summary>
        /// 键列表
        /// </summary>
        public List<TKey> GetKeys()
        {
            lock (lockObj)
            {
                return data.Keys.ToList();
            }
        }

        /// <summary>
        /// 值列表
        /// </summary>
        public List<TValue> GetValues()
        {
            lock (lockObj)
            {
                return data.Values.ToList();
            }
        }
    }
}